#ifndef COLOR_HPP
#define COLOR_HPP
#include "GLHeaders.hpp"
#include <cmath>

class Color{
public:
	GLubyte r, g, b, a;

public:
  /////////////////
	// Constructor //
  /////////////////

	Color(
      void);
  Color(
      const GLfloat fa);
	Color(
      const GLint ba);
	Color(
      const GLfloat fr, 
      const GLfloat fg, 
      const GLfloat fb, 
      const GLfloat fa=1.0f);
	Color(
      const GLint br, 
      const GLint bg, 
      const GLint bb, 
      const GLint ba=0xff);
	Color(
      const Color &color);

  ////////////////
  // Destructor //
  ////////////////

  ~Color(void);

  ///////////////////////////
	// Arithmetic operations //
  ///////////////////////////

  Color operator + () const;
  Color operator - () const;
	Color operator + (const Color    &rhs) const;
	Color operator + (const GLfloat value) const;
  Color operator + (const GLint   value) const;
	Color operator - (const Color   &rhs) const;
	Color operator - (const GLfloat value) const;
  Color operator - (const GLint   value) const;
	Color operator * (const Color    &rhs) const;
	Color operator * (const GLfloat value) const;
	Color operator / (const Color    &rhs) const;
	Color operator / (const GLfloat value) const;

  ////////////////////
	// Friend Methods //
  ////////////////////

	friend Color operator + (const GLfloat value, const Color &rhs);
	friend Color operator + (const GLint   value, const Color &rhs);
	friend Color operator - (const GLfloat value, const Color &rhs);
	friend Color operator - (const GLint   value, const Color &rhs);
  friend Color operator * (const GLfloat value, const Color &rhs);
	friend Color operator / (const GLfloat value, const Color &rhs);

  ////////////////////////
	// Arithmetic updates //
  ////////////////////////

	Color& operator  = (const Color    &rhs);
  Color& operator  = (const GLfloat value);
  Color& operator  = (const GLint   value);
  Color& operator += (const Color    &rhs);
  Color& operator += (const GLfloat value);
  Color& operator += (const GLint   value);
  Color& operator -= (const Color    &rhs);
  Color& operator -= (const GLfloat value);
  Color& operator -= (const GLint   value);
  Color& operator *= (const Color    &rhs);
	Color& operator *= (const GLfloat value);
	Color& operator /= (const Color    &rhs);
	Color& operator /= (const GLfloat value);

  //////////////////////
  // Useful functions //
  //////////////////////

  // f= foreground     | b = background
  // c = color channel | a = alpha channel
  Color Inverse(void);
  static Color Add(const Color &fg, const Color &bg);
  static Color Min(const Color &c0, const Color &c1);
  static Color Max(const Color &c0, const Color &c1);
  // Compute alpha chanel (1 - (1-fa)(1-ba))
  static inline GLubyte ComposeA(
      const GLubyte fa, 
      const GLubyte ba){
    return  (GLubyte)roundf((255.0f*255.0f - (255.0f-fa)*(255.0f-ba))/255.0f);
  };
  // Compute color channel ((1*fa*fc+(1-fa)*ba*bc) / (a*255))
  static inline GLubyte ComposeC(
      const GLubyte fa, 
      const GLubyte fc,
      const GLubyte ba, 
      const GLubyte bc,
      const GLubyte a){
    return (GLubyte)roundf(
        ((float)255.0f * fa * fc +
         (float)(255.0f - fa) * ba * bc )/
        ((float)255.0f * a));
  }; 
  static inline GLubyte ComposeC(
      const GLubyte fa, 
      const GLubyte fc,
      const GLubyte ba, 
      const GLubyte bc){
    return (GLubyte)roundf(
        ((float)255.0f * fa * fc +
         (float)(255.0f - fa) * ba * bc)/
        ((float)255.0f * ComposeA(fa, ba)));
  };

  ///////////////////
  // Special color //
  ///////////////////

	static const Color NONE;
	static const Color BLACK;
	static const Color BLUE;
	static const Color GREEN;
	static const Color CYAN;
	static const Color RED;
	static const Color MAGENTA;
	static const Color YELLOW;
	static const Color WHITE;
};

#endif
